<!DOCTYPE html>
<html>
	<head>
		<title>3DGlobe</title>
		<style type="text/css">
			html, body {margin: 0; padding: 0; overflow: hidden;}
			body { background: #000; }
		</style>
	</head>
	<body>
		<script type="text/javascript" src="js/three.min.js"></script>
		<script type="text/javascript" src="js/OrbitControls.js"></script>
		<script type="text/javascript" src="js/Tween.js"></script>
		<script language="javascript" type="text/javascript" src="geocentric.js"></script>
		<script language="javascript" type="text/javascript" src="jsonloader.js"></script>
		<script type="text/javascript">

		var renderer, scene, camera, controls,
			width = window.innerWidth,
			height = window.innerHeight;

		var raycaster, intersects;
		var mouse, INTERSECTED;

		var	coastlines, coastGroup,
			cities, cityGroup;

		var semiMajor3D = 150; //size of semi major axis in 3D-space
		var cameraDistance = 500; //initial camera distance, used to dynamically adjust fog parameters

		var listener, loader,
			sound;

		//introtween
		var position = { scale: 0, rotation: 0 };
		var target = { scale: 1, rotation: (Math.PI*2) * 1.75 };
		var introScaleTween = new TWEEN.Tween(position).to(target, 3000);
		introScaleTween.easing(TWEEN.Easing.Quartic.InOut);
		introScaleTween.onUpdate(function(){
			coastGroup.rotation.set(-(Math.PI / 2), 0, position.rotation);
			var scale = position.scale;
			coastGroup.scale.set(scale, scale, scale);
		});

		//citytween
		var cityStart = { scale: 3 };
		var cityEnd = {	scale: 1 };
		var cityTween = new TWEEN.Tween(cityStart).to(cityEnd, 3000);
		cityTween.easing(TWEEN.Easing.Exponential.In);
		cityTween.onUpdate(function(){
			var scale = cityStart.scale;
			cityGroup.scale.set(scale, scale, scale);
		});

		//loaddata
		//this is really messy, especially if I were to add more things to load. How to do it right?
		loadLineString("geodata/coastlines.geojson", semiMajor3D, function(data){
			coastlines = data;
			loadPoint("geodata/cities.geojson", semiMajor3D, function(data){
				cities = data;
				init();
			})
		});

		function init(){
			console.log("starting!");
			renderer = new THREE.WebGLRenderer();
			renderer.setSize(width, height);
			document.body.appendChild(renderer.domElement);

			camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000);

			camera.position.set(0, 0, cameraDistance);

			raycaster = new THREE.Raycaster();
			raycaster.params.Points.threshold = 20;
			mouse = new THREE.Vector2();

			//controls setup
			controls = new THREE.OrbitControls(camera, renderer.domElement);
			controls.addEventListener('change', render);
			controls.enablePan = false;
			controls.enableDamping = true;
			controls.minDistance = 200;
			controls.maxDistance = 700;
			controls.rotateSpeed = 0.1;
			controls.dampingFactor = 0.1;

			scene = new THREE.Scene();
			// scene.fog = new THREE.FogExp2(0x000000, 0.0025);

			setFog();

			listener= new THREE.AudioListener();
			loader = new THREE.AudioLoader();

			sound = new THREE.PositionalAudio(listener);
				// sound.setBuffer(hoverSoundBuffer);
			loader.load('sound/button-16.wav', function(buffer){
				sound.setBuffer(buffer);
				sound.setRefDistance(10);
				sound.play();
			})


			camera.add( listener );
			

			parseCoastlines();
			parseCitiesSpheres();

			// introScaleTween.start();
			// cityTween.start();
			animate();
			window.addEventListener( 'resize', onWindowResize, false );
			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
		}

		function onDocumentMouseMove( event ) {
				event.preventDefault();
				mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
		}

		function animate(){
			requestAnimationFrame(animate);
			controls.update();
			TWEEN.update();
			render();
		}

		function onWindowResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize( window.innerWidth, window.innerHeight );
		}

		function render(){
			raycaster.setFromCamera(mouse, camera);
			intersects = raycaster.intersectObjects(cityGroup.children);
			//if ( intersects.length > 0 ) console.log("intersect!!");
			handleIntersects();
			setFog();
			renderer.render(scene, camera);
		}

		function setFog(){
			cameraDistance = camera.position.distanceTo(new THREE.Vector3(0, 0, 0));
			scene.fog = new THREE.Fog(0x000000, cameraDistance - semiMajor3D, cameraDistance + semiMajor3D );		}

		function handleIntersects(){
			if ( intersects.length > 0 ) {
				if ( INTERSECTED != intersects[ 0 ].object ) {
					if ( INTERSECTED ) {
						INTERSECTED.material.color.set( INTERSECTED.currentHex );
						INTERSECTED.scale.set(1, 1, 1);
					}
					INTERSECTED = intersects[ 0 ].object;
					INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
					INTERSECTED.scale.set(3, 3, 3);
					sound.play();
					console.log(INTERSECTED.userData.name);
					INTERSECTED.material.color.set( 0xff5555 );
				}
			} else {
				if ( INTERSECTED ) {
						INTERSECTED.material.color.set( INTERSECTED.currentHex );
						INTERSECTED.scale.set(1, 1, 1);
					}
				INTERSECTED = null;
			}
		}

		// cities to three.js points
		function parseCities(){
			cityGroup = new THREE.Group();
			var city_material = new THREE.PointsMaterial({color: 0xff0000, size: 2});
			for(var feature = 0; feature < cities.features.length; feature++){
				var coordinates = cities.features[feature].geometry.coordinates;
				var geometry = new THREE.Geometry();
				var x = coordinates[0];
				var y = coordinates[1];
				var z = coordinates[2];
				geometry.vertices.push(new THREE.Vector3(x, y, z));
				var point = new THREE.Points(geometry, city_material);
				point.rotateX(-(Math.PI / 2));
				point.rotateZ(target.rotation);
				cityGroup.add(point);
			}
			scene.add(cityGroup);
		}

		function parseCitiesSpheres(){
			cityGroup = new THREE.Group();
			
			// var material = new THREE.MeshLambertMaterial( {color: 0xffaaaa} );
			for(var feature = 0; feature < cities.features.length; feature++){
				var material = new THREE.MeshBasicMaterial( { color: 0xffaa00, transparent: true, blending: THREE.AdditiveBlending } )
				var coordinates = cities.features[feature].geometry.coordinates;
				var geometry = new THREE.SphereGeometry(1, 8, 8);
				var x = coordinates[0];
				var y = coordinates[1];
				var z = coordinates[2];
				var sphere = new THREE.Mesh(geometry, material);
				sphere.position.set(x, y, z);
				sphere.userData = {
					name: cities.features[feature].properties.name
				};
				//sphere.add(sound);

				cityGroup.add(sphere);
			}
			cityGroup.rotateX(-(Math.PI / 2));
			cityGroup.rotateZ(target.rotation);
			scene.add(cityGroup);
		}

		// coastline coordinates to three.js lines
		function parseCoastlines(){
			coastGroup = new THREE.Group();
			var coastline_material = new THREE.LineBasicMaterial({color: 0xffffff});
			for(var feature = 0; feature < coastlines.features.length; feature++){
				var coordinates = coastlines.features[feature].geometry.coordinates;
				var geometry = new THREE.Geometry();
					for(var i = 0; i < coordinates.length; i+=1){
						var x = coordinates[i][0];
						var y = coordinates[i][1];
						var z = coordinates[i][2];
						geometry.vertices.push(new THREE.Vector3(x, y, z));
					}
				var line = new THREE.Line(geometry, coastline_material);
				coastGroup.add(line);
			}
			coastGroup.rotateX(-(Math.PI / 2));
			coastGroup.rotateZ(target.rotation);
			scene.add(coastGroup);
		}

		</script>
	</body> 
</html>
